<?php

namespace plugin\admin\app\controller;

use app\services\GoodsService;
use app\traits\DataProcessor;
use plugin\admin\app\common\Auth;
use plugin\admin\app\common\Util;
use plugin\admin\app\controller\Crud;
use plugin\admin\app\model\BrandCustomized;
use plugin\admin\app\model\Dealer;
use plugin\admin\app\model\GoodsActivityRelation;
use plugin\admin\app\model\GoodsAttr;
use plugin\admin\app\model\GoodsAttrValue;
use plugin\admin\app\model\GoodsBrand;
use plugin\admin\app\model\GoodsCategory;
use plugin\admin\app\model\GoodsCategoryRelation;
use plugin\admin\app\model\GoodsComment;
use plugin\admin\app\model\GoodsImage;
use plugin\admin\app\model\GoodsModel;
use plugin\admin\app\model\GoodsSKU;
use plugin\admin\app\model\GoodsSpec;
use plugin\admin\app\model\GoodsTag;
use plugin\admin\app\model\GoodsTagRelation;
use plugin\admin\app\model\ShoppingCart;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserLevel;
use plugin\admin\app\model\UserLevelGoods;
use support\Cache;
use support\Db;
use support\Request;
use support\Response;
use plugin\admin\app\model\Goods;
use support\exception\BusinessException;

/**
 * 商品列表
 */
class GoodController extends Crud
{

    /**
     * @var Goods
     */
    protected $model = null;

    /**
     * 构造函数
     * @return void
     */
    public function __construct()
    {
        $this->model = new Goods;
    }

    public function get(Request $request)
    {
        $goodses = Goods::all()->toArray();

        $data = [];
        foreach ($goodses as $goods) {
            $data[] = [
                'name' => $goods['id'] . ' ' . mb_substr($goods['name'], 0, 10) . ' <img src="' . $goods['thumb'] . '" width="50" />',
                'value' => $goods['id']
            ];
        }
        return $this->json(0, '成功', $data);
    }

    protected function selectInput(Request $request): array
    {
        $field = $request->get('field', 'id');
        $order = $request->get('order', 'desc');
        $format = $request->get('format', 'normal');
        $limit = (int)$request->get('limit', $format === 'tree' ? 1000 : 10);
        $limit = $limit <= 0 ? 10 : $limit;
        $order = $order === 'asc' ? 'asc' : 'desc';
        $where = $request->get();
        $page = (int)$request->get('page');
        $page = $page > 0 ? $page : 1;
        $categoryId = $request->get('category_id');
        $tagId = $request->get('tag_id');
        $table = config('plugin.admin.database.connections.mysql.prefix') . $this->model->getTable();

        $allow_column = Util::db()->select("desc `$table`");
        if (!$allow_column) {
            throw new BusinessException('表不存在');
        }
        $allow_column = array_column($allow_column, 'Field', 'Field');
        if (!in_array($field, $allow_column)) {
            $field = null;
        }
        foreach ($where as $column => $value) {
            if (
                $value === '' || !isset($allow_column[$column]) ||
                is_array($value) && (empty($value) || !in_array($value[0], ['null', 'not null']) && !isset($value[1]))
            ) {
                unset($where[$column]);
            }
        }
        // 按照数据限制字段返回数据
        if ($this->dataLimit === 'personal') {
            $where[$this->dataLimitField] = admin_id();
        } elseif ($this->dataLimit === 'auth') {
            $primary_key = $this->model->getKeyName();
            if (!Auth::isSupperAdmin() && (!isset($where[$primary_key]) || $this->dataLimitField != $primary_key)) {
                $where[$this->dataLimitField] = ['in', Auth::getScopeAdminIds(true)];
            }
        }

        if ($categoryId) {
            $relations = GoodsCategoryRelation::where('category_id', $categoryId)->get()->toArray();
            $goodsIds = array_column($relations, 'goods_id');

            if (count($goodsIds)) {
                $where['id'] = ['in', $goodsIds];
            } else {
                $where['id'] = 0;
            }
        }

        if ($tagId) {
            $relations = GoodsTagRelation::where('tag_id', $tagId)->get()->toArray();
            $goodsIds = array_column($relations, 'goods_id');

            if (count($goodsIds)) {
                $where['id'] = ['in', $goodsIds];
            } else {
                $where['id'] = 0;
            }
        }

        return [$where, $format, $limit, $field, $order, $page];
    }

    /**
     * 浏览
     * @return Response
     */
    public function index(): Response
    {
        return view('good/index');
    }

    public function search(Request $request): Response
    {
        $type = $request->get('type');

        $addUrl = '';
        $removeUrl = '';
        if ($type == 'activity') {
            $addUrl = '/app/admin/goods-activity/add';
            $removeUrl = '/app/admin/goods-activity/remove';
        }

        return view('good/search', [
            'id' => $request->get('id'),
            'type' => $type,
            'add_api' => $addUrl,
            'remove_api' => $removeUrl,
        ]);
    }

    protected function insertInput(Request $request): array
    {
        $data = $this->inputFilter($request->post());
        $password_filed = 'password';
        if (isset($data[$password_filed])) {
            $data[$password_filed] = Util::passwordHash($data[$password_filed]);
        }

        if (!Auth::isSupperAdmin() && $this->dataLimit) {
            if (!empty($data[$this->dataLimitField])) {
                $admin_id = $data[$this->dataLimitField];
                if (!in_array($admin_id, Auth::getScopeAdminIds(true))) {
                    throw new BusinessException('无数据权限');
                }
            }
        }

        DataProcessor::processSwitch($data, ['is_up', 'free_shipping', 'is_self_pickup', 'is_gift', 'is_recommend', 'is_normal']);

        if ($data['is_gift'] == 1) {
            throw new \Exception('新增报单产品功能未开放');
            if (empty($data['register_integral']) || empty($data['recharge_integral'])) {
                throw new \Exception('请设置注册积分和充值积分');
            }
        }

        $data['goods_no'] = GoodsService::generateNo();

        return $data;
    }

    /**
     * 插入
     * @param Request $request
     * @return Response
     * @throws BusinessException
     */
    public function insert(Request $request): Response
    {
        if ($request->method() === 'POST') {

            Db::beginTransaction();
            try {
                $originalData = $request->post();

                if (!empty($originalData['spec']['id'][0])) {
                    $spec = GoodsSpec::where('id', $originalData['spec']['id'][0])->first();
                    $specs = Cache::get('model-' . $spec['model_id']);

                    if ($specs) {
                        $specIds = array_column($specs, 'id');

                        GoodsSpec::where('model_id', $spec['model_id'])->whereNotIn('id', $specIds)->delete();
                        foreach ($specs as $spec) {
                            $id = $spec['id'];
                            unset($spec['id']);

                            $spec['is_temp'] = 0;
                            GoodsSpec::where('id', $id)->update($spec);
                        }

                        Cache::delete('model-' . $spec['model_id']);
                    }
                }


                $data = $this->insertInput($request);

                $data['thumb'] = isset($originalData['images']) && count($originalData['images']) > 0 ? $originalData['images'][0] : '';

                $id = $this->doInsert($data);

                if ($data['type'] == Goods::TYPE_SINGLE_SPEC) {
                    $originalData['skuspec'] = [];
                }

                $skuData = [];
                $totalStock = 0;
                foreach ($originalData['skuspec'] ?? [] as $key=>$spec) {
                    $totalStock += $originalData['skucount'][$key];
                    $skuData[] = ['goods_id' => $id, 'sku' => urldecode($spec), 'stock' => $originalData['skucount'][$key], 'price' => $originalData['skuprice'][$key], 'thumb' => $originalData['skuthumb'][$key]];
                }

                $attrs = [];
                foreach ($originalData['attrs']['id'] ?? [] as $index=>$attrValue) {
                    if ($attrValue) {
                        $attrs[] = ['goods_id' => $id, 'attr_id' => $attrValue, 'value' => $originalData['attrs']['value'][$index]];
                    }
                }

                $prices = array_column($skuData, 'price');

                if ($data['type'] == Goods::TYPE_MULTI_SPEC) {
                    if (!isset($data['price']) && count($prices) > 0) {
                        $price = min($prices);
                    } else {
                        $price = $data['price'];
                    }
                } else {
                    $price = $data['price'];
                    $totalStock = $data['stock'];
                }

                Goods::where('id', $id)->update(['price' => $price, 'stock' => $totalStock]);

                $categories = array_filter(explode(',', $originalData['category_id']));
                $categoryValue = [];

                if (count($categories) > 0) {
                    foreach ($categories as $category) {
                        $categoryValue[] = [
                            'goods_id' => $id,
                            'category_id' => $category
                        ];
                    }
                }

                if (isset($originalData['images']) && count($originalData['images']) > 0) {
                    $insertData = [];

                    foreach ($originalData['images'] as $image) {
                        $insertData[] = [
                            'goods_id' => $id,
                            'img_url' => $image
                        ];
                    }
                    GoodsImage::insert($insertData);
                }

                if (isset($originalData['tag_id']) && count($originalData['tag_id']) > 0) {
                    GoodsTagRelation::where('goods_id', $id)->delete();

                    $insertData = [];

                    foreach ($originalData['tag_id'] as $tagId) {
                        $insertData[] = [
                            'goods_id' => $id,
                            'tag_id' => $tagId
                        ];
                    }

                    GoodsTagRelation::insert($insertData);
                } else {
                    GoodsTagRelation::where('goods_id', $id)->delete();
                }

                if (count($categoryValue)) {
                    GoodsCategoryRelation::insert($categoryValue);
                }

                if (count($skuData)) {
                    GoodsSKU::insert($skuData);
                }

                if (count($attrs)) {
                    GoodsAttrValue::insert($attrs);
                }

                Db::commit();

                return $this->json(0, 'ok', ['id' => $id]);
            } catch (\Exception $e) {
                Db::rollBack();
                echo $e->getMessage() . $e->getTraceAsString();
                return $this->json(400, $e->getMessage());
            }
        }
        return view('good/insert', [
            'tags' => GoodsTag::all()->toArray()
        ]);
    }

    public function relation(Request $request): Response
    {
        if ($request->method() == 'POST') {
            $goodsId = $request->post('id');
            $userLevel = $request->post('level');
            $type = $request->post('type');

            switch ($type) {
                case 'user_level':
                    if (UserLevelGoods::where('goods_id', $goodsId)->where('level_id', $userLevel)->count() == 0) {
                        UserLevelGoods::insert([
                            'goods_id' => $goodsId,
                            'level_id' => $userLevel
                        ]);
                    }
                    break;
                case 'brand_customized':
                    BrandCustomized::where('id', $userLevel)->update(['goods_id' => $goodsId]);
                    break;
            }

            return $this->json(0, '关联成功');
        }

        $id = $request->get('id');
        return view('good/relation', [
            'id' => $id,
            'type' => $request->get('type', 'user_level'),
        ]);
    }

    protected function updateInput(Request $request): array
    {
        $primary_key = $this->model->getKeyName();
        $id = $request->post($primary_key);
        $data = $this->inputFilter($request->post());
        if (!Auth::isSupperAdmin() && $this->dataLimit && !empty($data[$this->dataLimitField])) {
            $admin_id = $data[$this->dataLimitField];
            if (!in_array($admin_id, Auth::getScopeAdminIds(true))) {
                throw new BusinessException('无数据权限');
            }
        }
        $password_filed = 'password';
        if (isset($data[$password_filed])) {
            // 密码为空，则不更新密码
            if ($data[$password_filed] === '') {
                unset($data[$password_filed]);
            } else {
                $data[$password_filed] = Util::passwordHash($data[$password_filed]);
            }
        }

        DataProcessor::processSwitch($data, ['is_up', 'free_shipping', 'is_self_pickup', 'is_gift', 'is_recommend', 'is_normal']);

        if ($data['is_gift'] == 1) {
            if (!in_array($data[$primary_key], [3, 4, 5])) {
                throw new \Exception('请勿将积分商品设置为报单产品');
            }
            if (empty($data['register_integral']) || empty($data['recharge_integral'])) {
                throw new \Exception('请设置注册积分和充值积分');
            }

            if ($data['is_normal'] == 1) {
                throw new \Exception('请勿同时设置该商品为报单产品与普通产品');
            }
        }

        unset($data[$primary_key]);
        return [$id, $data];
    }

    /**
     * 更新
     * @param Request $request
     * @return Response
     * @throws BusinessException
     */
    public function update(Request $request): Response
    {
        if ($request->method() === 'POST') {
            $originalData = $request->post();

            try {

                if (!empty($originalData['spec']['id'][0])) {
                    $spec = GoodsSpec::where('id', $originalData['spec']['id'][0])->first();
                    $specs = Cache::get('model-' . $spec['model_id']);

                    if ($specs) {
                        $specIds = array_column($specs, 'id');

                        GoodsSpec::where('model_id', $spec['model_id'])->whereNotIn('id', $specIds)->delete();
                        foreach ($specs as $spec) {
                            $id = $spec['id'];
                            unset($spec['id']);

                            $spec['is_temp'] = 0;
                            GoodsSpec::where('id', $id)->update($spec);
                        }

                        Cache::delete('model-' . $spec['model_id']);
                    }
                }


                [$id, $data] = $this->updateInput($request);

                $data['thumb'] = isset($originalData['images']) && count($originalData['images']) > 0 ? $originalData['images'][0] : '';

                $this->doUpdate($id, $data);

                $totalStock = $data['stock'] ?? 0;
                $skuData = [];
                $price = $data['price'];
                $skuMinPrice = $data['price'];
                foreach ($originalData['skuspec'] ?? [] as $key=>$spec) {
                    $totalStock += $originalData['skucount'][$key];

                    $skuInfo = GoodsSKU::where('goods_id', $id)->where('sku', urldecode($spec))->first();

                    if ($skuInfo) {
                        GoodsSku::where('id', $skuInfo['id'])->update(['stock' => $originalData['skucount'][$key], 'price' => $originalData['skuprice'][$key], 'thumb' => $originalData['skuthumb'][$key]]);
                        $skuMinPrice = min($skuMinPrice, $originalData['skuprice'][$key]);
                    } else {
                        $skuData[] = ['goods_id' => $id, 'sku' => urldecode($spec), 'stock' => $originalData['skucount'][$key], 'price' => $originalData['skuprice'][$key], 'thumb' => $originalData['skuthumb'][$key]];
                    }

                }

                foreach ($originalData['attrs']['id'] ?? [] as $index=>$attrValue) {
                    if ($attrValue) {
                        $attrInfo = GoodsAttrValue::where('goods_id', $id)->where('attr_id', $attrValue)->first();

                        if ($attrInfo) {
                            $attrInfo->value = $originalData['attrs']['value'][$index];
                            $attrInfo->save();
                        } else {
                            GoodsAttrValue::insert([
                                'goods_id' => $id,
                                'attr_id' => $attrValue,
                                'value' => $originalData['attrs']['value'][$index],
                            ]);
                        }

                    }
                }

                if ($data['type'] == Goods::TYPE_SINGLE_SPEC) {
                    $totalStock = $data['stock'];
                } else {

                    if (!isset($data['price'])) {
                        $price = $skuMinPrice;
                    }
                }

                Goods::where('id', $id)->update(['price' => $price, 'stock' => $totalStock]);

                $categories = array_filter(explode(',', $originalData['category_id']));
                $categoryValue = [];
                foreach ($categories as $category) {
                    $categoryValue[] = [
                        'goods_id' => $id,
                        'category_id' => $category
                    ];
                }

                if (isset($originalData['images']) && count($originalData['images']) > 0) {
                    GoodsImage::where('goods_id', $id)->delete();

                    $insertData = [];

                    foreach ($originalData['images'] as $image) {
                        $insertData[] = [
                            'goods_id' => $id,
                            'img_url' => $image
                        ];
                    }
                    GoodsImage::insert($insertData);
                } else {
                    GoodsImage::where('goods_id', $id)->delete();
                }

                if (isset($originalData['tag_id']) && count($originalData['tag_id']) > 0) {
                    GoodsTagRelation::where('goods_id', $id)->delete();

                    $insertData = [];

                    foreach ($originalData['tag_id'] as $tagId) {
                        $insertData[] = [
                            'goods_id' => $id,
                            'tag_id' => $tagId
                        ];
                    }

                    GoodsTagRelation::insert($insertData);
                } else {
                    GoodsTagRelation::where('goods_id', $id)->delete();
                }

                GoodsCategoryRelation::where('goods_id', $id)->delete();
                GoodsCategoryRelation::insert($categoryValue);

                if (count($skuData)) {
                    GoodsSKU::insert($skuData);
                }

                $skus = GoodsSKU::where('goods_id', $id)->get()->toArray();

                if (count($skus) > 0) {
                    $skuIds = [];
                    foreach ($skus as $sku) {
                        $isExists = false;
                        foreach ($originalData['skuspec'] ?? [] as $key=>$spec) {

                            if (urldecode($spec) == $sku['sku']) {
                                $isExists = true;
                                break;
                            }

                        }

                        if (!$isExists) {
                            $skuIds[] = $sku['id'];
                        }
                    }

                    if (count($skuIds) > 0) {
                        GoodsSKU::whereIn('id', $skuIds)->delete();
                    }
                }

                return $this->json(0);
            } catch (\Exception $e) {
                echo $e->getMessage() . $e->getTraceAsString();
                return $this->json(400, $e->getMessage());
            }
        }

        $id = $request->get('id');
        $goodsInfo = Goods::find($id)->toArray();
        $specs = GoodsSpec::where('model_id', $goodsInfo['model_id'])->where('is_temp', 0)->orderBy('sort')->get()->toArray();

        Cache::set('model-' . $goodsInfo['model_id'], $specs);
        GoodsSpec::where('model_id', $goodsInfo['model_id'])->where('is_temp', 1)->delete();


        $header = [];
        $arrs = [];
        foreach ($specs as $spec) {
            $header[] = $spec['name'];
            $arrs[] = explode(',', $spec['values']);
        }

        $header[] = '库存';
        $header[] = '价格';
        $header[] = '图片';

        $skuHtml = '<table class="layui-table">';

        $skuHtml .= '<tr>';
        foreach ($header as $value) {
            $skuHtml .= '<td>' . $value . '</td>';
        }

        $skuHtml .= '</tr>';

        $skus = cartesian_product($arrs);

        $skuInfos = GoodsSKU::where('goods_id', $id)->get()->toArray();

        foreach ($skus as $key=>$sku) {
            $skuHtml .= '<tr>';

            $skuJson = json_encode($sku, JSON_UNESCAPED_UNICODE);
            $skuStr = urlencode($skuJson);

            foreach ($skuInfos as $skuInfo) {
                if ($skuInfo['sku'] == $skuJson) {
                    break;
                }
            }

            foreach ($sku as $key=>$value) {
                $skuHtml .= <<< CONTENT
                <td>{$value}</td>
CONTENT;
            }

            $skuHtml .= '<td><input type="hidden" name="skuspec[]" value="' . $skuStr . '" /><input type="text" name="skucount[]" value="' . ($skuInfo['stock'] ?? 0) . '" class="layui-input"></td><td><input type="text" name="skuprice[]" value="' . ($skuInfo['price'] ?? 0) . '" class="layui-input"></td><td><img src="' . ($skuInfo['thumb'] ?? '') . '" width="100" /><input type="text" style="display:none" name="skuthumb[]" value="" />
                            <button type="button" class="pear-btn pear-btn-primary pear-btn-sm image" id="image'. $key .'" permission="app.admin.upload.avatar">
                                <i class="layui-icon layui-icon-upload"></i>上传图片
                            </button></td>';

            $skuHtml .= '</tr>';
        }

        $skuHtml .= '</table>';

        $attrValues = GoodsAttrValue::where('goods_id', $id)->get()->toArray();
        $attrs = GoodsAttr::where('model_id', $goodsInfo['model_id'])->orderBy('sort')->get()->toArray();

        $html = '<table class="layui-table">';

        $html .= '<tr><th>属性</th><th>属性值</th></tr>';

        foreach ($attrs as $attr) {
            foreach ($attrValues as $attrValue) {
                if ($attrValue['attr_id'] == $attr['id']) {
                    break;
                }
            }

            $value = $attrValue['value'] ?? 0;

            $html .= <<< EOF
            <tr>
                <td>{$attr['name']}</td>
                <td><input type="text" name="attr[{$attr['id']}]" value="{$value}" class="layui-input"></td></td>
            </tr>
EOF;

        }

        $html .= '</table>';

        $goodsCategories = GoodsCategoryRelation::where('goods_id', $id)->get()->toArray();
        $goodsCategoryIds = array_column($goodsCategories, 'category_id');

        $goodsInfo['support_pay_type'] = explode(',', $goodsInfo['support_pay_type']);

        $attrValues = array_combine(
            array_column($attrValues, 'attr_id'),
            array_values($attrValues)
        );

        $tags = GoodsTagRelation::where('goods_id', $id)->get()->toArray();
        $tagIds = array_column($tags, 'tag_id');

        return view('good/update', [
            'sku' => $skuHtml,
            'attr' => $html,
            'categoryIds' => join(',', $goodsCategoryIds),
            'goods_info' => $goodsInfo,
            'check_user_info' => !empty($goodsInfo['check_user_id']) ? User::find($goodsInfo['check_user_id']) : [],
            'images' => GoodsImage::where('goods_id', $id)->get()->toArray(),
            'specs' => $specs,
            'attrs' => $attrs,
            'attrValues' => $attrValues,
            'tags' => GoodsTag::all()->toArray(),
            'goods_tags' => $tagIds
        ]);
    }

    protected function formatNormal($items, $total): Response
    {
        try {
            $modelList = GoodsModel::list();
            $modelList = array_combine(
                array_column($modelList, 'value'),
                array_values($modelList)
            );
            $brandList = GoodsBrand::list();
            $brandList = array_combine(
                array_column($brandList, 'value'),
                array_values($brandList)
            );

            $searchParams = \request()->get('search_params');

            $type = $searchParams['type'] ?? '';

            if ($type == 'activity') {
                $goodsActivityRelations = GoodsActivityRelation::where('activity_id', $searchParams['id'])->get()->toArray();
            }

            foreach ($items as $key=>$item) {
                $items[$key]['model_text'] = $item['model_id'] ? $modelList[$item['model_id']]['name'] : '';
                $items[$key]['brand_text'] = $item['brand_id'] ? $brandList[$item['brand_id']]['name'] : '';

                if ($type == 'activity') {
                    $items[$key]['is_join'] = false;
                    foreach ($goodsActivityRelations as $activityRelation) {
                        if ($activityRelation['goods_id'] == $item['id']) {
                            $items[$key]['is_join'] = true;
                            break;
                        }
                    }
                }
            }
        } catch (\Exception $e) {
            echo $e->getMessage() . $e->getTraceAsString();
        }


        return json(['code' => 0, 'msg' => 'ok', 'count' => $total, 'data' => $items]);
    }

    public function delete(Request $request): Response
    {
        $ids = $this->deleteInput($request);
        $this->doDelete($ids);

        UserLevelGoods::whereIn('goods_id', $ids)->delete();
        GoodsCategoryRelation::whereIn('goods_id', $ids)->delete();
        GoodsImage::whereIn('goods_id', $ids)->delete();
        GoodsTagRelation::whereIn('goods_id', $ids)->delete();
        ShoppingCart::whereIn('goods_id', $ids)->delete();
        GoodsComment::whereIn('goods_id', $ids)->delete();
        return $this->json(0);
    }
}
